#pragma once
#include "QueryEvaluator.h"
#include "../auto/AutoTester/AbstractWrapper.h"

QueryEvaluator::QueryEvaluator()
{
	
}

QueryEvaluator::~QueryEvaluator()
{

}

void QueryEvaluator::SetQueryPreprocessor( QueryPreprocessor* preprocessor )
{
	this->_querypreprocessor = preprocessor;
}

list<string> QueryEvaluator::Evaluate( query_tree& _query_tree )
{
	vector<vector<string>> v = Evaluate_Now(_query_tree);
	vector<string> set;
	if ( !v.empty() )
		set = v.at(0);
	list<string> list(set.begin(), set.end());
	return list;
}

vector<vector<string>> QueryEvaluator::Evaluate_Now( query_tree& _query_tree )
{
	vector<query_declaration> variables = _query_tree.variables;
	vector<query_parameter> targets = _query_tree.targets;
	vector<ParameterType> targets_type;
	vector<string> targets_name;
	for (unsigned i = 0; i < targets.size(); i++)
	{
		targets_type.push_back(targets.at(i).type); // multiples
		targets_name.push_back(targets.at(i).value); // multiples
	}
	vector<query_relation> relations = _query_tree.relations;
	bool clause = true; // to determine if there exist a clause that is false
	vector<vector<string>> result;

	map<string, EntityType> types;
	map<string, int> indexes;
	map<string, vector<int>> values;
	bool relation_two_entities = false;
	vector<query_relation> with_entity;
	vector<query_relation> relations_with_two_entity;
	
	for (unsigned i = 0; i < targets_type.size(); i++)
	{
		if (targets_type.at(i) == ATTRIBUTE)
		{
			targets_type.at(i) = ENTITY;
			targets_name.at(i) = RemoveAttribute(targets_name.at(i));
		}
	}

	for (unsigned i = 0; i < variables.size(); i++)
	{
		types[variables.at(i).name] = variables.at(i).type;
		//	indexes[variables.at(i).name] = i;

		if (variables.at(i).type == kPROG_LINE)
			values[variables.at(i).name] = GetAllProgramLine();
		else if (variables.at(i).type == kSTMT)
			values[variables.at(i).name] = GetAllStatement();
		else if (variables.at(i).type == kASSIGN)
			values[variables.at(i).name] = GetAllAssign();
		else if (variables.at(i).type == kCALL)
			values[variables.at(i).name] = GetAllCall();
		else if (variables.at(i).type == kIF)
			values[variables.at(i).name] = GetAllIf();
		else if (variables.at(i).type == kWHILE)
			values[variables.at(i).name] = GetAllWhile();
		else if (variables.at(i).type == kCONSTANT)
			values[variables.at(i).name] = GetAllConstant();
		else if (variables.at(i).type == kPROCEDURE)
			values[variables.at(i).name] = GetAllProcIndex();
		else if (variables.at(i).type == kVARIABLE)
			values[variables.at(i).name] = GetAllVarIndex();
	}
	
	for (unsigned i = 0; i < relations.size(); i++)
	{
		if ((relations.at(i).parameters.at(0).type != ENTITY) &&
			(relations.at(i).parameters.at(0).type != ATTRIBUTE) &&
			(relations.at(i).parameters.at(1).type != ENTITY) &&		
			(relations.at(i).parameters.at(1).type != ATTRIBUTE))
			;

		else if (((relations.at(i).parameters.at(0).type == ENTITY) ||
			(relations.at(i).parameters.at(0).type == ATTRIBUTE)) &&
			((relations.at(i).parameters.at(1).type == ENTITY) ||	
			(relations.at(i).parameters.at(1).type == ATTRIBUTE)))
			relations_with_two_entity.push_back(relations.at(i));

		else if (relations.at(i).type == WITH)
			with_entity.push_back(relations.at(i));
	}
	
	for (unsigned i = 0; i < with_entity.size(); i++)
	{
		RelationType type = with_entity.at(i).type;
		string first_arg = with_entity.at(i).parameters.at(0).value;
		string second_arg = with_entity.at(i).parameters.at(1).value;
		ParameterType first_arg_type = with_entity.at(i).parameters.at(0).type;
		ParameterType second_arg_type = with_entity.at(i).parameters.at(1).type;
		vector<int> first_arg_set;
		vector<int> second_arg_set;

		if (type == WITH)
		{
			first_arg = RemoveAttribute(first_arg);

			if (second_arg_type == LINE)
			{
				vector<int> v;
				v.push_back(atoi(second_arg.c_str()));
				values[first_arg] = v;
			}
			else if (second_arg_type == NAME)
			{
				vector<int> v;
				if (types.find(first_arg)->second == kPROCEDURE)
				{
					if (PKB::procTable.GetProcIndex(second_arg) != -1)
						v.push_back(PKB::procTable.GetProcIndex(second_arg));
					values[first_arg] = v;
				}
				else if (types.find(first_arg)->second == kVARIABLE)
				{
					if (PKB::varTable.GetVarIndex(second_arg) != -1)
						v.push_back(PKB::varTable.GetVarIndex(second_arg));
					values[first_arg] = v;
				}
			}
		}

		this->_querypreprocessor->Update(first_arg, (values.find(first_arg)->second).size()); // update
	}

	query_relation relation;
	while (this->_querypreprocessor->DequeueRelation(relation))
	{	
		#if !SPA_PROJECT
			if (AbstractWrapper::GlobalStop)
			{
				return result;
			}
		#endif
		
		if (GetNumOfEntities(relation) == 0)
		{
			if (clause == true)
			{
				RelationType type = relation.type;
				string first_arg = relation.parameters.at(0).value;
				string second_arg = relation.parameters.at(1).value;
				ParameterType first_arg_type = relation.parameters.at(0).type;
				ParameterType second_arg_type = relation.parameters.at(1).type;
				vector<int> first_arg_set;
				vector<int> second_arg_set;
				vector<vector<int>> compute;

				if (first_arg_type == ANY && (type == CALLS || type == CALLS_T))
				{
					first_arg_set = GetAllProcIndex();
				}
				else if (first_arg_type == ANY && (type == AFFECTS || type == AFFECTS_T || type == AFFECTSBIP || type == AFFECTSBIP_T))
				{
					first_arg_set = GetAllAssign();
				}
				else if (first_arg_type == ANY)
				{
					first_arg_set = GetAllStatement();
				}
				else if (first_arg_type == LINE)
				{
					vector<int> v;
					v.push_back(atoi(first_arg.c_str()));
					first_arg_set = v;
				}
				else if (first_arg_type == NAME)
				{
					vector<int> v;
					if (PKB::procTable.GetProcIndex(first_arg) != -1)
						v.push_back(PKB::procTable.GetProcIndex(first_arg));
					first_arg_set = v;
				}

				if (second_arg_type == ANY && (type == CALLS || type == CALLS_T))
				{
					second_arg_set = GetAllProcIndex();
				}
				else if (second_arg_type == ANY && (type == MODIFIES_P || type == MODIFIES_S || type == USES_P || type == USES_S))
				{
					second_arg_set = GetAllVarIndex();
				}
				else if (second_arg_type == ANY && (type == AFFECTS || type == AFFECTS_T || type == AFFECTSBIP || type == AFFECTSBIP_T))
				{
					second_arg_set = GetAllAssign();
				}
				else if (second_arg_type == ANY)
				{
					second_arg_set = GetAllStatement();
				}
				else if (second_arg_type == LINE)
				{
					vector<int> v;
					v.push_back(atoi(second_arg.c_str()));
					second_arg_set = v;
				}
				else if (second_arg_type == NAME && (type == CALLS || type == CALLS_T))
				{
					vector<int> v;
					if (PKB::procTable.GetProcIndex(second_arg) != -1)
						v.push_back(PKB::procTable.GetProcIndex(second_arg));
					second_arg_set = v;
				}
				else if (second_arg_type == NAME)
				{
					vector<int> v;
					if (PKB::varTable.GetVarIndex(second_arg) != -1)
						v.push_back(PKB::varTable.GetVarIndex(second_arg));
					second_arg_set = v;
				} 

				if (type == MODIFIES_P)
					compute = _modifieshandle->FetchValidModifiesProcedureVar(first_arg_set, second_arg_set);
				else if (type == MODIFIES_S)
					compute = _modifieshandle->FetchValidModifiesStatementVar(first_arg_set, second_arg_set);
				else if (type == USES_P)
					compute = _useshandle->FetchValidUsesProcedureVar(first_arg_set, second_arg_set);
				else if (type == USES_S)
					compute = _useshandle->FetchValidUsesStatementVar(first_arg_set, second_arg_set);
				else if (type == FOLLOWS)
					compute = _followshandle->RetrieveFollows(first_arg_set, second_arg_set);
				else if (type == FOLLOWS_T)
					compute = _followshandle->RetrieveTransitiveFollows(first_arg_set, second_arg_set);
				else if (type == PARENT)
					compute = _parenthandle->RetrieveParent(first_arg_set, second_arg_set);
				else if (type == PARENT_T)
					compute = _parenthandle->RetrieveTransitiveParent(first_arg_set, second_arg_set);
				else if (type == NEXT)
					compute = _nexthandle->RetrieveNext(first_arg_set, second_arg_set);
				else if (type == NEXT_T)
					compute = _nexthandle->RetrieveTransitiveNext(first_arg_set, second_arg_set);
				else if (type == CALLS)
					compute = _callshandle->handleCalls(first_arg_set, second_arg_set);
				else if (type == CALLS_T)
					compute = _callshandle->handleCallsT(first_arg_set, second_arg_set);
				else if (type == AFFECTS)
					compute = _affectshandle->RetrieveAffects(first_arg_set, second_arg_set);
				else if (type == AFFECTS_T)
					compute = _affectshandle->RetrieveTransitiveAffects(first_arg_set, second_arg_set);
				else if (type == SIBLING)
					compute = _siblinghandle->RetrieveSibling(first_arg_set, second_arg_set);
				else if (type == AFFECTSBIP)
					compute = _affectsbiphandle->RetrieveAffectsBIP(first_arg_set, second_arg_set);
				else if (type == AFFECTSBIP_T)
					compute = _affectsbiphandle->RetrieveTransitiveAffectsBIP(first_arg_set, second_arg_set);
				else if (type == NEXTBIP)
					compute = _nextbiphandle->RetrieveNext(first_arg_set, second_arg_set);
				else if (type == NEXTBIP_T)
					compute = _nextbiphandle->RetrieveTransitiveNext(first_arg_set, second_arg_set);


				if (compute.size() == 0)
					clause = false;
				else if (compute.at(0).size() == 0)
					clause = false;
			}
		}

		else if (GetNumOfEntities(relation) == 1)
		{
			if (clause == true)
			{
				RelationType type = relation.type;
				string first_arg = relation.parameters.at(0).value;
				string second_arg = relation.parameters.at(1).value;
				ParameterType first_arg_type = relation.parameters.at(0).type;
				ParameterType second_arg_type = relation.parameters.at(1).type;
				vector<int> first_arg_set;
				vector<int> second_arg_set;

				if (type == WITH)
				{
					first_arg = RemoveAttribute(first_arg);

					if (second_arg_type == LINE)
					{
						vector<int> v;
						v.push_back(atoi(second_arg.c_str()));
						values[first_arg] = v;
					}
					else if (second_arg_type == NAME)
					{
						vector<int> v;
						if (types.find(first_arg)->second == kPROCEDURE)
						{
							if (PKB::procTable.GetProcIndex(second_arg) != -1)
								v.push_back(PKB::procTable.GetProcIndex(second_arg));
							values[first_arg] = v;
						}
						else if (types.find(first_arg)->second == kVARIABLE)
						{
							if (PKB::varTable.GetVarIndex(second_arg) != -1)
								v.push_back(PKB::varTable.GetVarIndex(second_arg));
							values[first_arg] = v;
						}
					}

					if (relation_two_entities == true)
					{
						for (unsigned i = 0; i < comb.size(); i++)
						{
							if (status.at(i) == 1)
							{
								unsigned j = 0;
								for (j; j < values.find(first_arg)->second.size(); j++)
									if (comb.at(i).at(indexes.find(first_arg)->second) == values.find(first_arg)->second.at(j))
										break;

								if (j == values.find(first_arg)->second.size())
									status.at(i) = 0;
							}
						}
					}

					this->_querypreprocessor->Update(first_arg, (values.find(first_arg)->second).size()); // update
				}
				else if (type == PATTERN_A || type == PATTERN_I || type == PATTERN_W)
				{
					if (type == PATTERN_A)
					{
						vector<int> list = values.find(first_arg)->second;
						string left = relation.parameters.at(1).value;
						string right = relation.parameters.at(2).value;
						ParameterType left_type = relation.parameters.at(1).type;
						ParameterType right_type = relation.parameters.at(2).type;
						int left_condition = 0, right_condition = 0;
						vector<int> left_list;

						if (left_type == ANY)
						{
							left = ""; // remove underscore
						}
						else
						{
							left_condition = 1;
							if (PKB::varTable.GetVarIndex(left) != -1)
								left_list.push_back(PKB::varTable.GetVarIndex(left));
						}

						if (right_type == ANY)
							right = ""; // remove underscore
						else if (right_type == EXPRESSION)
							right_condition = 1;
						else if (right_type == SUBEXPRESSION)
							right_condition = 2;

						if (!(left_type == ANY && right_type == ANY))
						{
							vector<vector<int>> v = _pattern.evaluateAssignV2(list, left_list, left_condition, right, right_condition);
							values[first_arg] = v.at(0);
							if (v.at(0).size() == 0)
								clause = false;

							if (relation_two_entities == true)
							{
								for (unsigned i = 0; i < comb.size(); i++)
								{
									if (status.at(i) == 1)
									{
										unsigned j = 0;
										for (j; j < values.find(first_arg)->second.size(); j++)
											if (comb.at(i).at(indexes.find(first_arg)->second) == values.find(first_arg)->second.at(j))
												break;

										if (j == values.find(first_arg)->second.size())
											status.at(i) = 0;
									}
								}
							}

							this->_querypreprocessor->Update(first_arg, (values.find(first_arg)->second).size()); // update
						}
					}
					else if (type == PATTERN_I || type == PATTERN_W)
					{
						if (second_arg_type != ANY)
						{
							vector<int> list = values.find(first_arg)->second;
							vector<int> left_list;
							if (PKB::varTable.GetVarIndex(second_arg) != -1)
								left_list.push_back(PKB::varTable.GetVarIndex(second_arg));
							vector<vector<int>> v = _pattern.evaluateWhileIfControlVariableV2(list, left_list, 1);
							values[first_arg] = v.at(0);
							if (v.at(0).size() == 0)
								clause = false;

							if (relation_two_entities == true)
							{
								for (unsigned i = 0; i < comb.size(); i++)
								{
									if (status.at(i) == 1)
									{
										unsigned j = 0;
										for (j; j < values.find(first_arg)->second.size(); j++)
											if (comb.at(i).at(indexes.find(first_arg)->second) == values.find(first_arg)->second.at(j))
												break;

										if (j == values.find(first_arg)->second.size())
											status.at(i) = 0;
									}
								}
							}

							this->_querypreprocessor->Update(first_arg, (values.find(first_arg)->second).size()); // update
						}
					}
				}
				else 
				{
					if (type == MODIFIES_P || type == USES_P || type == CALLS || type == CALLS_T)
					{
						if (first_arg_type == ENTITY)
						{
							first_arg_set = values.find(first_arg)->second;
						}
						else if (first_arg_type == NAME)
						{
							vector<int> v;
							if (PKB::procTable.GetProcIndex(first_arg) != -1)
								v.push_back(PKB::procTable.GetProcIndex(first_arg));
							first_arg_set = v;
						}
						else if (first_arg_type == ANY)
						{
							first_arg_set = GetAllProcIndex();
						}

						if (second_arg_type == ENTITY)
							second_arg_set = values.find(second_arg)->second;
						else if (second_arg_type == ANY && (type == MODIFIES_P || type == USES_P))
							second_arg_set = GetAllVarIndex();
						else if (second_arg_type == ANY && (type == CALLS || type == CALLS_T))
							second_arg_set = GetAllProcIndex();
						else if (second_arg_type == NAME && (type == MODIFIES_P || type == USES_P))
						{
							vector<int> v;
							if (PKB::varTable.GetVarIndex(second_arg) != -1)
								v.push_back(PKB::varTable.GetVarIndex(second_arg));
							second_arg_set = v;
						}
						else if (second_arg_type == NAME && (type == CALLS || type == CALLS_T))
						{
							vector<int> v;
							if (PKB::procTable.GetProcIndex(second_arg) != -1)
								v.push_back(PKB::procTable.GetProcIndex(second_arg));
							second_arg_set = v;
						}

						vector<vector<int>> compute;
						if (type == MODIFIES_P)
							compute = _modifieshandle->FetchValidModifiesProcedureVar(first_arg_set, second_arg_set);
						else if (type == USES_P)
							compute = _useshandle->FetchValidUsesProcedureVar(first_arg_set, second_arg_set);
						else if (type == CALLS)
							compute = _callshandle->handleCalls(first_arg_set, second_arg_set);
						else if (type == CALLS_T)
							compute = _callshandle->handleCallsT(first_arg_set, second_arg_set);

						if (compute.size() == 0)
							clause = false;
						else if (compute.at(0).size() == 0)
							clause = false;
						else
						{
							if (first_arg_type == ENTITY)
							{
								values[first_arg] = RemoveDuplicates(compute.at(0));
								this->_querypreprocessor->Update(first_arg, (values.find(first_arg)->second).size()); // update

								if (relation_two_entities == true)
								{
									for (unsigned i = 0; i < comb.size(); i++)
									{
										if (status.at(i) == 1)
										{
											unsigned j = 0;
											for (j; j < values.find(first_arg)->second.size(); j++)
												if (comb.at(i).at(indexes.find(first_arg)->second) == values.find(first_arg)->second.at(j))
													break;

											if (j == values.find(first_arg)->second.size())
												status.at(i) = 0;
										}
									}
								}
							}

							if (second_arg_type == ENTITY)
							{
								values[second_arg] = RemoveDuplicates(compute.at(1));
								this->_querypreprocessor->Update(second_arg, (values.find(second_arg)->second).size()); // update

								if (relation_two_entities == true)
								{
									for (unsigned i = 0; i < comb.size(); i++)
									{
										if (status.at(i) == 1)
										{
											unsigned j = 0;
											for (j; j < values.find(second_arg)->second.size(); j++)
												if (comb.at(i).at(indexes.find(second_arg)->second) == values.find(second_arg)->second.at(j))
													break;

											if (j == values.find(second_arg)->second.size())
												status.at(i) = 0;
										}
									}
								}
							}
						}
					}
					else if (type == MODIFIES_S || type == USES_S)
					{
						if (first_arg_type == ENTITY)
							first_arg_set = values.find(first_arg)->second;
						else if (first_arg_type == LINE)
						{
							vector<int> v;
							v.push_back(atoi(first_arg.c_str()));
							first_arg_set = v;
						}

						if (second_arg_type == ENTITY)
							second_arg_set = values.find(second_arg)->second;
						else if (second_arg_type == ANY)
							second_arg_set = GetAllVarIndex();
						else if (second_arg_type == NAME)
						{
							vector<int> v;
							if (PKB::varTable.GetVarIndex(second_arg) != -1)
								v.push_back(PKB::varTable.GetVarIndex(second_arg));
							second_arg_set = v;
						}

						vector<vector<int>> compute;
						if (type == MODIFIES_S)
							compute = _modifieshandle->FetchValidModifiesStatementVar(first_arg_set, second_arg_set);
						else if (type == USES_S)
							compute = _useshandle->FetchValidUsesStatementVar(first_arg_set, second_arg_set);

						if (compute.size() == 0)
							clause = false;
						else if (compute.at(0).size() == 0)
							clause = false;
						else
						{
							if (first_arg_type == ENTITY)
							{
								values[first_arg] = RemoveDuplicates(compute.at(0));
								this->_querypreprocessor->Update(first_arg, (values.find(first_arg)->second).size()); // update

								if (relation_two_entities == true)
								{
									for (unsigned i = 0; i < comb.size(); i++)
									{
										if (status.at(i) == 1)
										{
											unsigned j = 0;
											for (j; j < values.find(first_arg)->second.size(); j++)
												if (comb.at(i).at(indexes.find(first_arg)->second) == values.find(first_arg)->second.at(j))
													break;

											if (j == values.find(first_arg)->second.size())
												status.at(i) = 0;
										}
									}
								}
							}

							if (second_arg_type == ENTITY)
							{
								values[second_arg] = RemoveDuplicates(compute.at(1));
								this->_querypreprocessor->Update(second_arg, (values.find(second_arg)->second).size()); // update

								if (relation_two_entities == true)
								{
									for (unsigned i = 0; i < comb.size(); i++)
									{
										if (status.at(i) == 1)
										{
											unsigned j = 0;
											for (j; j < values.find(second_arg)->second.size(); j++)
												if (comb.at(i).at(indexes.find(second_arg)->second) == values.find(second_arg)->second.at(j))
													break;

											if (j == values.find(second_arg)->second.size())
												status.at(i) = 0;
										}
									}
								}
							}
						}
					}
					else if (type == PARENT || type == PARENT_T ||
						type == FOLLOWS || type == FOLLOWS_T ||
						type == NEXT || type == NEXT_T ||
						type == AFFECTS || type == AFFECTS_T ||
						type == NEXTBIP || type == NEXTBIP_T ||
						type == AFFECTSBIP || type == AFFECTSBIP_T ||
						type == SIBLING)
					{
						if (first_arg_type == ENTITY)
							first_arg_set = values.find(first_arg)->second;
						else if (first_arg_type == ANY && (type == AFFECTS || type == AFFECTS_T || type == AFFECTSBIP || type == AFFECTSBIP_T))
							first_arg_set = GetAllAssign();
						else if (first_arg_type == ANY)
							first_arg_set = GetAllStatement();
						else if (first_arg_type == LINE)
						{
							vector<int> v;
							v.push_back(atoi(first_arg.c_str()));
							first_arg_set = v;
						}

						if (second_arg_type == ENTITY)
							second_arg_set = values.find(second_arg)->second;
						else if (second_arg_type == ANY && (type == AFFECTS || type == AFFECTS_T || type == AFFECTSBIP || type == AFFECTSBIP_T))
							second_arg_set = GetAllAssign();
						else if (second_arg_type == ANY)
							second_arg_set = GetAllStatement();
						else if (second_arg_type == LINE)
						{
							vector<int> v;
							v.push_back(atoi(second_arg.c_str()));
							second_arg_set = v;
						}

						vector<vector<int>> compute;
						if (type == FOLLOWS)
							compute = _followshandle->RetrieveFollows(first_arg_set, second_arg_set);
						else if (type == FOLLOWS_T)
							compute = _followshandle->RetrieveTransitiveFollows(first_arg_set, second_arg_set);
						else if (type == PARENT)
							compute = _parenthandle->RetrieveParent(first_arg_set, second_arg_set);
						else if (type == PARENT_T)
							compute = _parenthandle->RetrieveTransitiveParent(first_arg_set, second_arg_set);
						else if (type == NEXT)
							compute = _nexthandle->RetrieveNext(first_arg_set, second_arg_set);
						else if (type == NEXT_T)
							compute = _nexthandle->RetrieveTransitiveNext(first_arg_set, second_arg_set);
						else if (type == AFFECTS)
							compute = _affectshandle->RetrieveAffects(first_arg_set, second_arg_set);
						else if (type == AFFECTS_T)
							compute = _affectshandle->RetrieveTransitiveAffects(first_arg_set, second_arg_set);
						else if (type == SIBLING)
							compute = _siblinghandle->RetrieveSibling(first_arg_set, second_arg_set);
						else if (type == AFFECTSBIP)
							compute = _affectsbiphandle->RetrieveAffectsBIP(first_arg_set, second_arg_set);
						else if (type == AFFECTSBIP_T)
							compute = _affectsbiphandle->RetrieveTransitiveAffectsBIP(first_arg_set, second_arg_set);
						else if (type == NEXTBIP)
							compute = _nextbiphandle->RetrieveNext(first_arg_set, second_arg_set);
						else if (type == NEXTBIP_T)
							compute = _nextbiphandle->RetrieveTransitiveNext(first_arg_set, second_arg_set);

						if (compute.size() == 0)
							clause = false;
						else if (compute.at(0).size() == 0)
							clause = false;
						else
						{
							if (first_arg_type == ENTITY)
							{
								values[first_arg] = RemoveDuplicates(compute.at(0));
								this->_querypreprocessor->Update(first_arg, (values.find(first_arg)->second).size()); // update

								if (relation_two_entities == true)
								{
									for (unsigned i = 0; i < comb.size(); i++)
									{
										if (status.at(i) == 1)
										{
											unsigned j = 0;
											for (j; j < values.find(first_arg)->second.size(); j++)
												if (comb.at(i).at(indexes.find(first_arg)->second) == values.find(first_arg)->second.at(j))
													break;

											if (j == values.find(first_arg)->second.size())
												status.at(i) = 0;
										}
									}
								}
							}

							if (second_arg_type == ENTITY)
							{
								values[second_arg] = RemoveDuplicates(compute.at(1));
								this->_querypreprocessor->Update(second_arg, (values.find(second_arg)->second).size()); // update

								if (relation_two_entities == true)
								{
									for (unsigned i = 0; i < comb.size(); i++)
									{
										if (status.at(i) == 1)
										{
											unsigned j = 0;
											for (j; j < values.find(second_arg)->second.size(); j++)
												if (comb.at(i).at(indexes.find(second_arg)->second) == values.find(second_arg)->second.at(j))
													break;

											if (j == values.find(second_arg)->second.size())
												status.at(i) = 0;
										}
									}
								}
							}
						}
					}
				}
			}
		}

		else if (GetNumOfEntities(relation) == 2 && clause == true)
		{
			if (relations_with_two_entity.size() > 0)
			{
				int count_with = 0;
				for (unsigned i = 0; i < relations_with_two_entity.size(); i++)
					if (relations_with_two_entity.at(i).type == WITH)
						count_with++;

				for (int i = 0; i < count_with; i++)
					for (unsigned j = 0; j < relations_with_two_entity.size(); j++)
						if (relations_with_two_entity.at(j).type == WITH)
							if (types[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(0).value)] == kPROCEDURE &&
								types[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(1).value)] == kVARIABLE)
							{
								vector<string> set0;
								vector<string> set1;
								vector<string> setR;
								vector<int> setA;
								vector<int> setB;
								for (unsigned k = 0; k < values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(0).value)].size(); k++)
									set0.push_back(PKB::procTable.GetProcName(values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(0).value)].at(k)));
								for (unsigned k = 0; k < values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(1).value)].size(); k++)
									set1.push_back(PKB::varTable.GetVarName(values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(1).value)].at(k)));

								for (unsigned k = 0; k < set0.size(); k++)
									for (unsigned l = 0; l < set1.size(); l++)
										if (set0.at(k).compare(set1.at(l)) == 0)
											setR.push_back(set0.at(k));

								for (unsigned k = 0; k < setR.size(); k++)
								{
									setA.push_back(PKB::procTable.GetProcIndex(setR.at(k)));
									setB.push_back(PKB::varTable.GetVarIndex(setR.at(k)));
								}

								values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(0).value)] = RemoveDuplicates(setA);
								values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(1).value)] = RemoveDuplicates(setB);
							}
							else if (types[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(0).value)] == kVARIABLE &&
								types[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(1).value)] == kPROCEDURE)
							{
								vector<string> set0;
								vector<string> set1;
								vector<string> setR;
								vector<int> setA;
								vector<int> setB;
								for (unsigned k = 0; k < values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(0).value)].size(); k++)
									set0.push_back(PKB::varTable.GetVarName(values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(0).value)].at(k)));
								for (unsigned k = 0; k < values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(1).value)].size(); k++)
									set1.push_back(PKB::procTable.GetProcName(values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(1).value)].at(k)));

								for (unsigned k = 0; k < set0.size(); k++)
									for (unsigned l = 0; l < set1.size(); l++)
										if (set0.at(k).compare(set1.at(l)) == 0)
											setR.push_back(set0.at(k));

								for (unsigned k = 0; k < setR.size(); k++)
								{
									setA.push_back(PKB::varTable.GetVarIndex(setR.at(k)));
									setB.push_back(PKB::procTable.GetProcIndex(setR.at(k)));		
								}

								values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(0).value)] = RemoveDuplicates(setA);
								values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(1).value)] = RemoveDuplicates(setB);
							}
							else
							{
								vector<int> intersection;
								intersection = SetIntersection(values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(0).value)],
									values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(1).value)]);
								values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(0).value)] = intersection;
								values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(1).value)] = intersection;
							}
			}

			if (relation_two_entities == false)
			{
				vector<int> accum;
				vector<vector<int>> arr;
				int index = 0;
				for (unsigned i = 0; i < variables.size(); i++)
				{
					int count = 0;
					for (unsigned j = 0; j < relations.size(); j++)
						if (RemoveAttribute(relations.at(j).parameters.at(0).value).compare(variables.at(i).name) == 0 ||
							RemoveAttribute(relations.at(j).parameters.at(1).value).compare(variables.at(i).name) == 0)
							count++;

					for (unsigned j = 0; j < targets_name.size(); j++)
						if (count != 0 || variables.at(i).name.compare(targets_name.at(j)) == 0)
						{
							indexes[variables.at(i).name] = index;
							arr.push_back(values.find(variables.at(i).name)->second);
							index++;
							break;
						}
				}

				combinations(arr, 0, accum);
				#if !SPA_PROJECT
					if (AbstractWrapper::GlobalStop)
					{
						return result;
					}
				#endif
				vector<int> temp (comb.size());
				status = temp;
				fill(status.begin(), status.end(), 1);
				relation_two_entities = true;
			}

			if (relation_two_entities == true)
			{
				if (GetNumOfEntities(relation) == 2)
				{
					for (unsigned i = 0; i < comb.size(); i++)
					{
						if (i % 50 == 0)
						{
							#if !SPA_PROJECT
								if (AbstractWrapper::GlobalStop)
								{
									return result;
								}
							#endif
						}

						if (status.at(i) == 1)
						{
							RelationType type = relation.type;
							string first_arg = relation.parameters.at(0).value;
							string second_arg = relation.parameters.at(1).value;
							ParameterType first_arg_type = relation.parameters.at(0).type;
							ParameterType second_arg_type = relation.parameters.at(1).type;
							vector<int> first_arg_set;
							vector<int> second_arg_set;
							vector<vector<int>> compute;
							first_arg = RemoveAttribute(first_arg);
							second_arg = RemoveAttribute(second_arg);
							first_arg_set.push_back(comb.at(i).at(indexes.find(first_arg)->second));
							second_arg_set.push_back(comb.at(i).at(indexes.find(second_arg)->second));
							
							if (type == MODIFIES_P)
								compute = _modifieshandle->FetchValidModifiesProcedureVar(first_arg_set, second_arg_set);
							else if (type == MODIFIES_S)
								compute = _modifieshandle->FetchValidModifiesStatementVar(first_arg_set, second_arg_set);
							else if (type == USES_P)
								compute = _useshandle->FetchValidUsesProcedureVar(first_arg_set, second_arg_set);
							else if (type == USES_S)
								compute = _useshandle->FetchValidUsesStatementVar(first_arg_set, second_arg_set);
							else if (type == FOLLOWS)
								compute = _followshandle->RetrieveFollows(first_arg_set, second_arg_set);
							else if (type == FOLLOWS_T)
								compute = _followshandle->RetrieveTransitiveFollows(first_arg_set, second_arg_set);
							else if (type == PARENT)
								compute = _parenthandle->RetrieveParent(first_arg_set, second_arg_set);
							else if (type == PARENT_T)
								compute = _parenthandle->RetrieveTransitiveParent(first_arg_set, second_arg_set);
							else if (type == NEXT)
								compute = _nexthandle->RetrieveNext(first_arg_set, second_arg_set);
							else if (type == NEXT_T)
								compute = _nexthandle->RetrieveTransitiveNext(first_arg_set, second_arg_set);
							else if (type == CALLS)
								compute = _callshandle->handleCalls(first_arg_set, second_arg_set);
							else if (type == CALLS_T)
								compute = _callshandle->handleCallsT(first_arg_set, second_arg_set);
							else if (type == AFFECTS)
								compute = _affectshandle->RetrieveAffects(first_arg_set, second_arg_set);
							else if (type == AFFECTS_T)
								compute = _affectshandle->RetrieveTransitiveAffects(first_arg_set, second_arg_set);
							else if (type == SIBLING)
								compute = _siblinghandle->RetrieveSibling(first_arg_set, second_arg_set);
							else if (type == AFFECTSBIP)
								compute = _affectsbiphandle->RetrieveAffectsBIP(first_arg_set, second_arg_set);
							else if (type == AFFECTSBIP_T)
								compute = _affectsbiphandle->RetrieveTransitiveAffectsBIP(first_arg_set, second_arg_set);
							else if (type == NEXTBIP)
								compute = _nextbiphandle->RetrieveNext(first_arg_set, second_arg_set);
							else if (type == NEXTBIP_T)
								compute = _nextbiphandle->RetrieveTransitiveNext(first_arg_set, second_arg_set);

							else if (type == WITH)
							{
								if (types[first_arg] == kPROCEDURE && types[second_arg] == kVARIABLE)
								{
									if (PKB::procTable.GetProcName(comb.at(i).at(indexes.find(first_arg)->second)).compare
										(PKB::varTable.GetVarName(comb.at(i).at(indexes.find(second_arg)->second))) != 0)
									{
										status.at(i) = 0;
										updates(indexes.find(first_arg)->second, indexes.find(second_arg)->second, 
											comb.at(i).at(indexes.find(first_arg)->second), comb.at(i).at(indexes.find(second_arg)->second), i+1);
									}
								}
								else if (types[first_arg] == kVARIABLE && types[second_arg] == kPROCEDURE)
								{
									if (PKB::varTable.GetVarName(comb.at(i).at(indexes.find(first_arg)->second)).compare
										(PKB::procTable.GetProcName(comb.at(i).at(indexes.find(second_arg)->second))) != 0)
									{
										status.at(i) = 0;
										updates(indexes.find(first_arg)->second, indexes.find(second_arg)->second, 
											comb.at(i).at(indexes.find(first_arg)->second), comb.at(i).at(indexes.find(second_arg)->second), i+1);
									}
								}
								else if (comb.at(i).at(indexes.find(first_arg)->second) != comb.at(i).at(indexes.find(second_arg)->second))
								{
									status.at(i) = 0;
									updates(indexes.find(first_arg)->second, indexes.find(second_arg)->second, 
										comb.at(i).at(indexes.find(first_arg)->second), comb.at(i).at(indexes.find(second_arg)->second), i+1);
								}
							}
							else if (type == PATTERN_A || type == PATTERN_I || type == PATTERN_W)
							{
								if (type == PATTERN_A)
								{
									string third_arg = relation.parameters.at(2).value;
									ParameterType third_arg_type = relation.parameters.at(2).type;
									int left_condition = 1, right_condition = 0;

									if (third_arg_type == ANY)
										third_arg = ""; // remove underscore
									else if (third_arg_type == EXPRESSION)
										right_condition = 1;
									else if (third_arg_type == SUBEXPRESSION)
										right_condition = 2;

									vector<vector<int>> v = _pattern.evaluateAssignV2(first_arg_set, second_arg_set, left_condition, third_arg, right_condition);
									if (v.at(0).size() == 0)
									{
										status.at(i) = 0;
									}
								}
								else if (type == PATTERN_I || type == PATTERN_W)
								{
									vector<vector<int>> v = _pattern.evaluateWhileIfControlVariableV2(first_arg_set, second_arg_set, 1);
									if (v.at(0).size() == 0)
									{
										status.at(i) = 0;
										updates(indexes.find(first_arg)->second, indexes.find(second_arg)->second, 
											comb.at(i).at(indexes.find(first_arg)->second), comb.at(i).at(indexes.find(second_arg)->second), i+1);
									}
								}
							}
							
							if (compute.size() == 0)
							{
								if (type != WITH && type != PATTERN_A && type != PATTERN_I && type != PATTERN_W)
								{
									status.at(i) = 0;
									updates(indexes.find(first_arg)->second, indexes.find(second_arg)->second, 
										comb.at(i).at(indexes.find(first_arg)->second), comb.at(i).at(indexes.find(second_arg)->second), i+1);
								}
							}
							else if (type != WITH && type != PATTERN_A && type != PATTERN_I && type != PATTERN_W && compute.at(0).size() == 0)
							{
								status.at(i) = 0;
								updates(indexes.find(first_arg)->second, indexes.find(second_arg)->second, 
									comb.at(i).at(indexes.find(first_arg)->second), comb.at(i).at(indexes.find(second_arg)->second), i+1);
							}
						}
					}

					vector<int> first_arg_set1;
					vector<int> second_arg_set1;
					string first_arg = relation.parameters.at(0).value;
					string second_arg = relation.parameters.at(1).value;
					first_arg = RemoveAttribute(first_arg);
					second_arg = RemoveAttribute(second_arg);
					for (unsigned i = 0; i < comb.size(); i++)
					{
						if (i % 50 == 0)
						{
							#if !SPA_PROJECT
								if (AbstractWrapper::GlobalStop)
								{
									return result;
								}
							#endif
						}

						if (status.at(i) == 1)
						{
							first_arg_set1.push_back(comb.at(i).at(indexes.find(first_arg)->second));
							second_arg_set1.push_back(comb.at(i).at(indexes.find(second_arg)->second));
						}
					}

					values[first_arg] = RemoveDuplicates(first_arg_set1);
					values[second_arg] = RemoveDuplicates(second_arg_set1);
					this->_querypreprocessor->Update(first_arg, values.find(first_arg)->second.size()); // update
					this->_querypreprocessor->Update(second_arg, values.find(second_arg)->second.size()); // update
				}
			}
		}
	}

	if (relations_with_two_entity.size() == 0 && clause == true)
	{
		if (targets_type.size() == 1 && targets_type.at(0) == BOOL)
		{
			vector<string> s1;
			string boo = "true";
			s1.push_back(boo);
			vector<vector<string>> r;
			r.push_back(s1);
			return r;
		}
		else
		{
			if (targets_type.size() == 1)
			{
				vector<int> v = values.find(targets_name.at(0))->second;
				vector<string> s;
				if (types.find(targets_name.at(0))->second == kVARIABLE) 
				{
					for (unsigned i = 0; i < v.size(); i++)
						s.push_back(PKB::varTable.GetVarName(v.at(i)));
					result.push_back(s);
				}
				else if (types.find(targets_name.at(0))->second == kPROCEDURE)
				{
					for (unsigned i = 0; i < v.size(); i++)
						s.push_back(PKB::procTable.GetProcName(v.at(i)));
					result.push_back(s);
				}
				else
				{
					for (unsigned i = 0; i < v.size(); i++)
					{
						stringstream ss;
						ss << v.at(i);
						s.push_back(ss.str());
					}
					result.push_back(s);
				}
				return result;
			}
			else
			{
				// for more targets
				vector<int> accum;
				vector<vector<int>> arr;
				vector<string> s;
				vector<string> elem;
				map<string, int> ind;
				int cout = 0;

				for (unsigned i = 0; i < targets_name.size(); i++)
					if (i == 0 || find(elem.begin(), elem.end(), targets_name.at(i)) == elem.end())
					{
						arr.push_back(values.find(targets_name.at(i))->second);
						elem.push_back(targets_name.at(i));
						ind[targets_name.at(i)] = cout;
						cout++;
					}

				combinations(arr, 0, accum);

				for (unsigned i = 0; i < comb.size(); i++)
				{
					stringstream ss;
					string temp;
					for (unsigned j = 0; j < targets_name.size(); j++)
					{
						if (types.find(targets_name.at(j))->second == kVARIABLE)
						{
							temp = PKB::varTable.GetVarName(comb.at(i).at(ind.find(targets_name.at(j))->second));
						}
						else if (types.find(targets_name.at(j))->second == kPROCEDURE)
							temp = PKB::procTable.GetProcName(comb.at(i).at(ind.find(targets_name.at(j))->second));
						else
						{
							stringstream ss1;
							ss1 << comb.at(i).at(ind.find(targets_name.at(j))->second);
							temp = ss1.str();
						}

						if (j != targets_name.size() - 1)
							ss << temp << " ";
						else
							ss << temp;
					}
					s.push_back(ss.str());
				}
				vector<vector<int>> v;
				comb = v;
				result.push_back(s);
			}
		}
	}

	if (targets_type.size() == 1 && targets_type.at(0) == BOOL)
	{
		vector<string> s;
		string boo = "true";
		int count = 0;
		for (unsigned i = 0; i < status.size(); i++)
		{
			if (status.at(i) == 1)
				count++;
		}

		if (clause == false || count == 0)
			boo = "false";

		s.push_back(boo);
		result.push_back(s);
	}
	else
	{
		if (targets_type.size() == 1)
		{
			if (clause == true)
			{
				string boo = "true";
				int count = 0;
				for (unsigned i = 0; i < status.size(); i++)
				{
					if (status.at(i) == 1)
						count++;
				}
				if (count == 0)
					boo = "false";

				if (boo.compare("true") == 0)
				{
					int index = indexes.find(targets_name.at(0))->second;
					vector<int> v;
					for (unsigned i = 0; i < status.size(); i++)
						if (status.at(i) == 1)
							v.push_back(comb.at(i).at(index));
					v = RemoveDuplicates(v);

					if (types.find(targets_name.at(0))->second == kVARIABLE) 
					{
						vector<string> s;
						for (unsigned i = 0; i < v.size(); i++)
							s.push_back(PKB::varTable.GetVarName(v.at(i)));
						result.push_back(s);
					}
					else if (types.find(targets_name.at(0))->second == kPROCEDURE)
					{
						vector<string> s;
						for (unsigned i = 0; i < v.size(); i++)
							s.push_back(PKB::procTable.GetProcName(v.at(i)));
						result.push_back(s);
					}
					else
					{
						vector<string> s;
						for (unsigned i = 0; i < v.size(); i++)
						{
							stringstream ss;
							ss << v.at(i);
							s.push_back(ss.str());
						}
						result.push_back(s);
					}
				}
			}
		}
		else
		{
			// for more targets
			string boo = "true";
			int count = 0;
			for (unsigned i = 0; i < status.size(); i++)
			{
				if (status.at(i) == 1)
					count++;
			}
			if (count == 0)
				boo = "false";

			if (boo.compare("true") == 0)
			{
				vector<string> s;
				for (unsigned i = 0; i < status.size(); i++)
				{
					if (status.at(i) == 1)
					{
						stringstream ss;
						string temp;
						for (unsigned j = 0; j < targets_name.size(); j++)
						{
							int index = indexes.find(targets_name.at(j))->second;
							if (types.find(targets_name.at(j))->second == kVARIABLE)
								temp = PKB::varTable.GetVarName(comb.at(i).at(index));
							else if (types.find(targets_name.at(j))->second == kPROCEDURE)
								temp = PKB::procTable.GetProcName(comb.at(i).at(index));
							else
							{
								stringstream ss1;
								ss1 << comb.at(i).at(index);
								temp = ss1.str();
							}

							if (j != targets_name.size() - 1)
								ss << temp << " ";
							else
								ss << temp;
						}

						if (find(s.begin(), s.end(), ss.str()) == s.end())
							s.push_back(ss.str());
					}
				}
					result.push_back(s);
			}
		}
	}

	vector<vector<int>> v1;
	comb = v1;
	vector<int> v2;
	status = v2;
	return result;	
}


vector<vector<string>> QueryEvaluator::Evaluate_Now2( query_tree& _query_tree )
{
	vector<query_declaration> variables = _query_tree.variables;
	vector<query_parameter> targets = _query_tree.targets;
	vector<ParameterType> targets_type;
	vector<string> targets_name;
	for (unsigned i = 0; i < targets.size(); i++)
	{
		targets_type.push_back(targets.at(i).type); // multiples
		targets_name.push_back(targets.at(i).value); // multiples
	}
	vector<query_relation> relations = _query_tree.relations;
	bool clause = true; // to determine if there exist a clause that is false
	vector<vector<string>> result;

	map<string, EntityType> types;
	map<string, int> indexes;
	map<string, vector<int>> values;
	vector<query_relation> relations_with_no_entity;
	vector<query_relation> relations_with_one_entity;
	vector<query_relation> relations_with_two_entity;

	for (unsigned i = 0; i < targets_type.size(); i++)
	{
		if (targets_type.at(i) == ATTRIBUTE)
		{
			targets_type.at(i) = ENTITY;
			targets_name.at(i) = RemoveAttribute(targets_name.at(i));
		}
	}

	for (unsigned i = 0; i < variables.size(); i++)
	{
		types[variables.at(i).name] = variables.at(i).type;
		//	indexes[variables.at(i).name] = i;

		if (variables.at(i).type == kPROG_LINE)
			values[variables.at(i).name] = GetAllProgramLine();
		else if (variables.at(i).type == kSTMT)
			values[variables.at(i).name] = GetAllStatement();
		else if (variables.at(i).type == kASSIGN)
			values[variables.at(i).name] = GetAllAssign();
		else if (variables.at(i).type == kCALL)
			values[variables.at(i).name] = GetAllCall();
		else if (variables.at(i).type == kIF)
			values[variables.at(i).name] = GetAllIf();
		else if (variables.at(i).type == kWHILE)
			values[variables.at(i).name] = GetAllWhile();
		else if (variables.at(i).type == kCONSTANT)
			values[variables.at(i).name] = GetAllConstant();
		else if (variables.at(i).type == kPROCEDURE)
			values[variables.at(i).name] = GetAllProcIndex();
		else if (variables.at(i).type == kVARIABLE)
			values[variables.at(i).name] = GetAllVarIndex();
	}

	for (unsigned i = 0; i < relations.size(); i++)
	{
		if ((relations.at(i).parameters.at(0).type != ENTITY) &&
			(relations.at(i).parameters.at(0).type != ATTRIBUTE) &&
			(relations.at(i).parameters.at(1).type != ENTITY) &&		
			(relations.at(i).parameters.at(1).type != ATTRIBUTE))
			relations_with_no_entity.push_back(relations.at(i));

		else if (((relations.at(i).parameters.at(0).type == ENTITY) ||
			(relations.at(i).parameters.at(0).type == ATTRIBUTE)) &&
			((relations.at(i).parameters.at(1).type == ENTITY) ||	
			(relations.at(i).parameters.at(1).type == ATTRIBUTE)))
			relations_with_two_entity.push_back(relations.at(i));

		else
			relations_with_one_entity.push_back(relations.at(i));		
	}

	for (unsigned i = 0; i < relations_with_no_entity.size(); i++)
	{
		if (clause == true)
		{
			RelationType type = relations_with_no_entity.at(i).type;
			string first_arg = relations_with_no_entity.at(i).parameters.at(0).value;
			string second_arg = relations_with_no_entity.at(i).parameters.at(1).value;
			ParameterType first_arg_type = relations_with_no_entity.at(i).parameters.at(0).type;
			ParameterType second_arg_type = relations_with_no_entity.at(i).parameters.at(1).type;
			vector<int> first_arg_set;
			vector<int> second_arg_set;
			vector<vector<int>> compute;

			if (first_arg_type == ANY && (type == CALLS || type == CALLS_T))
			{
				first_arg_set = GetAllProcIndex();
			}
			else if (first_arg_type == ANY)
			{
				first_arg_set = GetAllStatement();
			}
			else if (first_arg_type == LINE)
			{
				vector<int> v;
				v.push_back(atoi(first_arg.c_str()));
				first_arg_set = v;
			}
			else if (first_arg_type == NAME)
			{
				vector<int> v;
				if (PKB::procTable.GetProcIndex(first_arg) != -1)
					v.push_back(PKB::procTable.GetProcIndex(first_arg));
				first_arg_set = v;
			}


			if (second_arg_type == ANY && (type == CALLS || type == CALLS_T))
			{
				second_arg_set = GetAllProcIndex();
			}
			else if (second_arg_type == ANY && (type == MODIFIES_P || type == MODIFIES_S || type == USES_P || type == USES_S))
			{
				second_arg_set = GetAllVarIndex();
			}
			else if (second_arg_type == ANY)
			{
				second_arg_set = GetAllStatement();
			}
			else if (second_arg_type == LINE)
			{
				vector<int> v;
				v.push_back(atoi(second_arg.c_str()));
				second_arg_set = v;
			}
			else if (second_arg_type == NAME && (type == CALLS || type == CALLS_T))
			{
				vector<int> v;
				if (PKB::procTable.GetProcIndex(second_arg) != -1)
					v.push_back(PKB::procTable.GetProcIndex(second_arg));
				second_arg_set = v;
			}
			else if (second_arg_type == NAME)
			{
				vector<int> v;
				if (PKB::varTable.GetVarIndex(second_arg) != -1)
					v.push_back(PKB::varTable.GetVarIndex(second_arg));
				second_arg_set = v;
			} 

			if (type == MODIFIES_P)
				compute = _modifieshandle->FetchValidModifiesProcedureVar(first_arg_set, second_arg_set);
			else if (type == MODIFIES_S)
				compute = _modifieshandle->FetchValidModifiesStatementVar(first_arg_set, second_arg_set);
			else if (type == USES_P)
				compute = _useshandle->FetchValidUsesProcedureVar(first_arg_set, second_arg_set);
			else if (type == USES_S)
				compute = _useshandle->FetchValidUsesStatementVar(first_arg_set, second_arg_set);
			else if (type == FOLLOWS)
				compute = _followshandle->RetrieveFollows(first_arg_set, second_arg_set);
			else if (type == FOLLOWS_T)
				compute = _followshandle->RetrieveTransitiveFollows(first_arg_set, second_arg_set);
			else if (type == PARENT)
				compute = _parenthandle->RetrieveParent(first_arg_set, second_arg_set);
			else if (type == PARENT_T)
				compute = _parenthandle->RetrieveTransitiveParent(first_arg_set, second_arg_set);
			else if (type == NEXT)
				compute = _nexthandle->RetrieveNext(first_arg_set, second_arg_set);
			else if (type == NEXT_T)
				compute = _nexthandle->RetrieveTransitiveNext(first_arg_set, second_arg_set);
			else if (type == CALLS)
				compute = _callshandle->handleCalls(first_arg_set, second_arg_set);
			else if (type == CALLS_T)
				compute = _callshandle->handleCallsT(first_arg_set, second_arg_set);
			else if (type == AFFECTS)
				compute = _affectshandle->RetrieveAffects(first_arg_set, second_arg_set);
			else if (type == AFFECTS_T)
				compute = _affectshandle->RetrieveTransitiveAffects(first_arg_set, second_arg_set);

			if (compute.size() == 0)
				clause = false;
			else if (compute.at(0).size() == 0)
				clause = false;
		}
	}

	for (unsigned i = 0; i < relations_with_one_entity.size(); i++)
	{
		if (clause == true)
		{
			RelationType type = relations_with_one_entity.at(i).type;
			string first_arg = relations_with_one_entity.at(i).parameters.at(0).value;
			string second_arg = relations_with_one_entity.at(i).parameters.at(1).value;
			ParameterType first_arg_type = relations_with_one_entity.at(i).parameters.at(0).type;
			ParameterType second_arg_type = relations_with_one_entity.at(i).parameters.at(1).type;
			vector<int> first_arg_set;
			vector<int> second_arg_set;

			if (type == WITH)
			{
				first_arg = RemoveAttribute(first_arg);

				if (second_arg_type == LINE)
				{
					vector<int> v;
					v.push_back(atoi(second_arg.c_str()));
					values[first_arg] = v;
				}
				else if (second_arg_type == NAME)
				{
					vector<int> v;
					if (types.find(first_arg)->second == kPROCEDURE)
					{
						if (PKB::procTable.GetProcIndex(second_arg) != -1)
							v.push_back(PKB::procTable.GetProcIndex(second_arg));
						values[first_arg] = v;
					}
					else if (types.find(first_arg)->second == kVARIABLE)
					{
						if (PKB::varTable.GetVarIndex(second_arg) != -1)
							v.push_back(PKB::varTable.GetVarIndex(second_arg));
						values[first_arg] = v;
					}
				}
			}
			else if (type == PATTERN_A || type == PATTERN_I || type == PATTERN_W)
			{
				if (type == PATTERN_A)
				{
					vector<int> list = values.find(first_arg)->second;
					string left = relations_with_one_entity.at(i).parameters.at(1).value;
					string right = relations_with_one_entity.at(i).parameters.at(2).value;
					ParameterType left_type = relations_with_one_entity.at(i).parameters.at(1).type;
					ParameterType right_type = relations_with_one_entity.at(i).parameters.at(2).type;
					int left_condition = 0, right_condition = 0;
					vector<int> left_list;

					if (left_type == ANY)
					{
						left = ""; // remove underscore
					}
					else
					{
						left_condition = 1;
						if (PKB::varTable.GetVarIndex(left) != -1)
							left_list.push_back(PKB::varTable.GetVarIndex(left));
					}

					if (right_type == ANY)
						right = ""; // remove underscore
					else if (right_type == EXPRESSION)
						right_condition = 1;
					else if (right_type == SUBEXPRESSION)
						right_condition = 2;

					if (!(left_type == ANY && right_type == ANY))
					{
						vector<vector<int>> v = _pattern.evaluateAssignV2(list, left_list, left_condition, right, right_condition);
						values[first_arg] = v.at(0);
						if (v.at(0).size() == 0)
							clause = false;
					}
				}
				else if (type == PATTERN_I || type == PATTERN_W)
				{
					if (second_arg_type != ANY)
					{
						vector<int> list = values.find(first_arg)->second;
						vector<int> left_list;
						if (PKB::varTable.GetVarIndex(second_arg) != -1)
							left_list.push_back(PKB::varTable.GetVarIndex(second_arg));
						vector<vector<int>> v = _pattern.evaluateWhileIfControlVariableV2(list, left_list, 1);
						values[first_arg] = v.at(0);
						if (v.at(0).size() == 0)
							clause = false;
					}
				}
			}
			else 
			{
				if (type == MODIFIES_P || type == USES_P || type == CALLS || type == CALLS_T)
				{
					if (first_arg_type == ENTITY)
					{
						first_arg_set = values.find(first_arg)->second;
					}
					else if (first_arg_type == NAME)
					{
						vector<int> v;
						if (PKB::procTable.GetProcIndex(first_arg) != -1)
							v.push_back(PKB::procTable.GetProcIndex(first_arg));
						first_arg_set = v;
					}
					else if (first_arg_type == ANY)
					{
						first_arg_set = GetAllProcIndex();
					}

					if (second_arg_type == ENTITY)
						second_arg_set = values.find(second_arg)->second;
					else if (second_arg_type == ANY && (type == MODIFIES_P || type == USES_P))
						second_arg_set = GetAllVarIndex();
					else if (second_arg_type == ANY && (type == CALLS || type == CALLS_T))
						second_arg_set = GetAllProcIndex();
					else if (second_arg_type == NAME && (type == MODIFIES_P || type == USES_P))
					{
						vector<int> v;
						if (PKB::varTable.GetVarIndex(second_arg) != -1)
							v.push_back(PKB::varTable.GetVarIndex(second_arg));
						second_arg_set = v;
					}
					else if (second_arg_type == NAME && (type == CALLS || type == CALLS_T))
					{
						vector<int> v;
						if (PKB::procTable.GetProcIndex(second_arg) != -1)
							v.push_back(PKB::procTable.GetProcIndex(second_arg));
						second_arg_set = v;
					}

					vector<vector<int>> compute;
					if (type == MODIFIES_P)
						compute = _modifieshandle->FetchValidModifiesProcedureVar(first_arg_set, second_arg_set);
					else if (type == USES_P)
						compute = _useshandle->FetchValidUsesProcedureVar(first_arg_set, second_arg_set);
					else if (type == CALLS)
						compute = _callshandle->handleCalls(first_arg_set, second_arg_set);
					else if (type == CALLS_T)
						compute = _callshandle->handleCallsT(first_arg_set, second_arg_set);

					if (compute.size() == 0)
						clause = false;
					else if (compute.at(0).size() == 0)
						clause = false;
					else
					{
						if (first_arg_type == ENTITY)
							values[first_arg] = RemoveDuplicates(compute.at(0));
						if (second_arg_type == ENTITY)
							values[second_arg] = RemoveDuplicates(compute.at(1));
					}
				}
				else if (type == MODIFIES_S || type == USES_S)
				{
					if (first_arg_type == ENTITY)
						first_arg_set = values.find(first_arg)->second;
					else if (first_arg_type == LINE)
					{
						vector<int> v;
						v.push_back(atoi(first_arg.c_str()));
						first_arg_set = v;
					}

					if (second_arg_type == ENTITY)
						second_arg_set = values.find(second_arg)->second;
					else if (second_arg_type == ANY)
						second_arg_set = GetAllVarIndex();
					else if (second_arg_type == NAME)
					{
						vector<int> v;
						if (PKB::varTable.GetVarIndex(second_arg) != -1)
							v.push_back(PKB::varTable.GetVarIndex(second_arg));
						second_arg_set = v;
					}

					vector<vector<int>> compute;
					if (type == MODIFIES_S)
						compute = _modifieshandle->FetchValidModifiesStatementVar(first_arg_set, second_arg_set);
					else if (type == USES_S)
						compute = _useshandle->FetchValidUsesStatementVar(first_arg_set, second_arg_set);

					if (compute.size() == 0)
						clause = false;
					else if (compute.at(0).size() == 0)
						clause = false;
					else
					{
						if (first_arg_type == ENTITY)
							values[first_arg] = RemoveDuplicates(compute.at(0));
						if (second_arg_type == ENTITY)
							values[second_arg] = RemoveDuplicates(compute.at(1));
					}
				}
				else if (type == PARENT || type == PARENT_T ||
					type == FOLLOWS || type == FOLLOWS_T ||
					type == NEXT || type == NEXT_T ||
					type == AFFECTS || type == AFFECTS_T)
				{
					if (first_arg_type == ENTITY)
						first_arg_set = values.find(first_arg)->second;
					else if (first_arg_type == ANY)
						first_arg_set = GetAllStatement();
					else if (first_arg_type == LINE)
					{
						vector<int> v;
						v.push_back(atoi(first_arg.c_str()));
						first_arg_set = v;
					}

					if (second_arg_type == ENTITY)
						second_arg_set = values.find(second_arg)->second;
					else if (second_arg_type == ANY)
						second_arg_set = GetAllStatement();
					else if (second_arg_type == LINE)
					{
						vector<int> v;
						v.push_back(atoi(second_arg.c_str()));
						second_arg_set = v;
					}

					vector<vector<int>> compute;
					if (type == FOLLOWS)
						compute = _followshandle->RetrieveFollows(first_arg_set, second_arg_set);
					else if (type == FOLLOWS_T)
						compute = _followshandle->RetrieveTransitiveFollows(first_arg_set, second_arg_set);
					else if (type == PARENT)
						compute = _parenthandle->RetrieveParent(first_arg_set, second_arg_set);
					else if (type == PARENT_T)
						compute = _parenthandle->RetrieveTransitiveParent(first_arg_set, second_arg_set);
					else if (type == NEXT)
						compute = _nexthandle->RetrieveNext(first_arg_set, second_arg_set);
					else if (type == NEXT_T)
						compute = _nexthandle->RetrieveTransitiveNext(first_arg_set, second_arg_set);
					else if (type == AFFECTS)
						compute = _affectshandle->RetrieveAffects(first_arg_set, second_arg_set);
					else if (type == AFFECTS_T)
						compute = _affectshandle->RetrieveTransitiveAffects(first_arg_set, second_arg_set);

					if (compute.size() == 0)
						clause = false;
					else if (compute.at(0).size() == 0)
						clause = false;
					else
					{
						if (first_arg_type == ENTITY)
							values[first_arg] = RemoveDuplicates(compute.at(0));
						if (second_arg_type == ENTITY)
							values[second_arg] = RemoveDuplicates(compute.at(1));
					}
				}
			}
		}
	}

	if (relations_with_two_entity.size() > 0)
	{
		int count_with = 0;
		for (unsigned i = 0; i < relations_with_two_entity.size(); i++)
			if (relations_with_two_entity.at(i).type == WITH)
				count_with++;

		for (int i = 0; i < count_with; i++)
			for (unsigned j = 0; j < relations_with_two_entity.size(); j++)
				if (relations_with_two_entity.at(j).type == WITH)
					if (types[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(0).value)] == kPROCEDURE &&
						types[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(1).value)] == kVARIABLE)
					{
						vector<string> set0;
						vector<string> set1;
						vector<string> setR;
						vector<int> setA;
						vector<int> setB;
						for (unsigned k = 0; k < values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(0).value)].size(); k++)
							set0.push_back(PKB::procTable.GetProcName(values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(0).value)].at(k)));
						for (unsigned k = 0; k < values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(1).value)].size(); k++)
							set1.push_back(PKB::varTable.GetVarName(values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(1).value)].at(k)));

						for (unsigned k = 0; k < set0.size(); k++)
							for (unsigned l = 0; l < set1.size(); l++)
								if (set0.at(k).compare(set1.at(l)) == 0)
									setR.push_back(set0.at(k));

						for (unsigned k = 0; k < setR.size(); k++)
						{
							setA.push_back(PKB::procTable.GetProcIndex(setR.at(k)));
							setB.push_back(PKB::varTable.GetVarIndex(setR.at(k)));
						}

						values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(0).value)] = RemoveDuplicates(setA);
						values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(1).value)] = RemoveDuplicates(setB);
					}
					else if (types[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(0).value)] == kVARIABLE &&
						types[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(1).value)] == kPROCEDURE)
					{
						vector<string> set0;
						vector<string> set1;
						vector<string> setR;
						vector<int> setA;
						vector<int> setB;
						for (unsigned k = 0; k < values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(0).value)].size(); k++)
							set0.push_back(PKB::varTable.GetVarName(values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(0).value)].at(k)));
						for (unsigned k = 0; k < values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(1).value)].size(); k++)
							set1.push_back(PKB::procTable.GetProcName(values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(1).value)].at(k)));

						for (unsigned k = 0; k < set0.size(); k++)
							for (unsigned l = 0; l < set1.size(); l++)
								if (set0.at(k).compare(set1.at(l)) == 0)
									setR.push_back(set0.at(k));

						for (unsigned k = 0; k < setR.size(); k++)
						{
							setA.push_back(PKB::varTable.GetVarIndex(setR.at(k)));
							setB.push_back(PKB::procTable.GetProcIndex(setR.at(k)));		
						}

						values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(0).value)] = RemoveDuplicates(setA);
						values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(1).value)] = RemoveDuplicates(setB);
					}
					else
					{
						vector<int> intersection;
						intersection = SetIntersection(values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(0).value)],
							values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(1).value)]);
						values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(0).value)] = intersection;
						values[RemoveAttribute(relations_with_two_entity.at(j).parameters.at(1).value)] = intersection;
					}

					vector<int> accum;
					vector<vector<int>> arr;
					int index = 0;
					for (unsigned i = 0; i < variables.size(); i++)
					{
						int count = 0;
						for (unsigned j = 0; j < relations_with_two_entity.size(); j++)
							if (RemoveAttribute(relations_with_two_entity.at(j).parameters.at(0).value).compare(variables.at(i).name) == 0 ||
								RemoveAttribute(relations_with_two_entity.at(j).parameters.at(1).value).compare(variables.at(i).name) == 0)
								count++;

						for (unsigned j = 0; j < targets_name.size(); j++)
							if (count != 0 || variables.at(i).name.compare(targets_name.at(j)) == 0)
							{
								indexes[variables.at(i).name] = index;
								arr.push_back(values.find(variables.at(i).name)->second);
								index++;
								break;
							}
					}
					combinations(arr, 0, accum);	
				//	for (unsigned i = 0; i < comb.size(); i++)
				//		status.push_back(1);

					vector<int> temp (comb.size());
					status = temp;
					fill(status.begin(), status.end(), 1);
	}
	else if (clause == true)
	{
		if (targets_type.size() == 1 && targets_type.at(0) == BOOL)
		{
			vector<string> s1;
			string boo = "true";
			s1.push_back(boo);
			vector<vector<string>> r;
			r.push_back(s1);
			return r;
		}
		else
		{
			if (targets_type.size() == 1)
			{
				vector<int> v = values.find(targets_name.at(0))->second;
				vector<string> s;
				if (types.find(targets_name.at(0))->second == kVARIABLE) 
				{
					for (unsigned i = 0; i < v.size(); i++)
						s.push_back(PKB::varTable.GetVarName(v.at(i)));
					result.push_back(s);
				}
				else if (types.find(targets_name.at(0))->second == kPROCEDURE)
				{
					for (unsigned i = 0; i < v.size(); i++)
						s.push_back(PKB::procTable.GetProcName(v.at(i)));
					result.push_back(s);
				}
				else
				{
					for (unsigned i = 0; i < v.size(); i++)
					{
						stringstream ss;
						ss << v.at(i);
						s.push_back(ss.str());
					}
					result.push_back(s);
				}
				return result;
			}
			else
			{
				// for more targets
				vector<int> accum;
				vector<vector<int>> arr;
				vector<string> s;
				vector<string> elem;
				map<string, int> ind;
				int cout = 0;

				for (unsigned i = 0; i < targets_name.size(); i++)
					if (i == 0 || find(elem.begin(), elem.end(), targets_name.at(i)) == elem.end())
					{
						arr.push_back(values.find(targets_name.at(i))->second);
						elem.push_back(targets_name.at(i));
						ind[targets_name.at(i)] = cout;
						cout++;
					}

				combinations(arr, 0, accum);

				#if !SPA_PROJECT
					if (AbstractWrapper::GlobalStop)
					{
						return result;
					}
				#endif

				for (unsigned i = 0; i < comb.size(); i++)
				{
					stringstream ss;
					string temp;
					for (unsigned j = 0; j < targets_name.size(); j++)
					{
						if (types.find(targets_name.at(j))->second == kVARIABLE)
						{
							temp = PKB::varTable.GetVarName(comb.at(i).at(ind.find(targets_name.at(j))->second));
						}
						else if (types.find(targets_name.at(j))->second == kPROCEDURE)
							temp = PKB::procTable.GetProcName(comb.at(i).at(ind.find(targets_name.at(j))->second));
						else
						{
							stringstream ss1;
							ss1 << comb.at(i).at(ind.find(targets_name.at(j))->second);
							temp = ss1.str();
						}

						if (j != targets_name.size() - 1)
							ss << temp << " ";
						else
							ss << temp;
					}
					s.push_back(ss.str());
				}
				vector<vector<int>> v;
				comb = v;
				result.push_back(s);
			}
		}
	}

	for (unsigned i = 0; i < comb.size(); i++)
	{
		if (status.at(i) == 1)
		{
			for (unsigned j = 0; j < relations_with_two_entity.size(); j++)
			{
				RelationType type = relations_with_two_entity.at(j).type;
				string first_arg = relations_with_two_entity.at(j).parameters.at(0).value;
				string second_arg = relations_with_two_entity.at(j).parameters.at(1).value;
				ParameterType first_arg_type = relations_with_two_entity.at(j).parameters.at(0).type;
				ParameterType second_arg_type = relations_with_two_entity.at(j).parameters.at(1).type;
				vector<int> first_arg_set;
				vector<int> second_arg_set;
				vector<vector<int>> compute;

				first_arg = RemoveAttribute(first_arg);
				second_arg = RemoveAttribute(second_arg);
				first_arg_set.push_back(comb.at(i).at(indexes.find(first_arg)->second));
				second_arg_set.push_back(comb.at(i).at(indexes.find(second_arg)->second));

				if (type == MODIFIES_P)
					compute = _modifieshandle->FetchValidModifiesProcedureVar(first_arg_set, second_arg_set);
				else if (type == MODIFIES_S)
					compute = _modifieshandle->FetchValidModifiesStatementVar(first_arg_set, second_arg_set);
				else if (type == USES_P)
					compute = _useshandle->FetchValidUsesProcedureVar(first_arg_set, second_arg_set);
				else if (type == USES_S)
					compute = _useshandle->FetchValidUsesStatementVar(first_arg_set, second_arg_set);
				else if (type == FOLLOWS)
					compute = _followshandle->RetrieveFollows(first_arg_set, second_arg_set);
				else if (type == FOLLOWS_T)
					compute = _followshandle->RetrieveTransitiveFollows(first_arg_set, second_arg_set);
				else if (type == PARENT)
					compute = _parenthandle->RetrieveParent(first_arg_set, second_arg_set);
				else if (type == PARENT_T)
					compute = _parenthandle->RetrieveTransitiveParent(first_arg_set, second_arg_set);
				else if (type == NEXT)
					compute = _nexthandle->RetrieveNext(first_arg_set, second_arg_set);
				else if (type == NEXT_T)
					compute = _nexthandle->RetrieveTransitiveNext(first_arg_set, second_arg_set);
				else if (type == CALLS)
					compute = _callshandle->handleCalls(first_arg_set, second_arg_set);
				else if (type == CALLS_T)
					compute = _callshandle->handleCallsT(first_arg_set, second_arg_set);
				else if (type == AFFECTS)
					compute = _affectshandle->RetrieveAffects(first_arg_set, second_arg_set);
				else if (type == AFFECTS_T)
					compute = _affectshandle->RetrieveTransitiveAffects(first_arg_set, second_arg_set);

				else if (type == WITH)
				{
					if (types[first_arg] == kPROCEDURE && types[second_arg] == kVARIABLE)
					{
						if (PKB::procTable.GetProcName(comb.at(i).at(indexes.find(first_arg)->second)).compare
							(PKB::varTable.GetVarName(comb.at(i).at(indexes.find(second_arg)->second))) != 0)
						{
							status.at(i) = 0;
							updates(indexes.find(first_arg)->second, indexes.find(second_arg)->second, 
								comb.at(i).at(indexes.find(first_arg)->second), comb.at(i).at(indexes.find(second_arg)->second), i+1);
						}
					}
					else if (types[first_arg] == kVARIABLE && types[second_arg] == kPROCEDURE)
					{
						if (PKB::varTable.GetVarName(comb.at(i).at(indexes.find(first_arg)->second)).compare
							(PKB::procTable.GetProcName(comb.at(i).at(indexes.find(second_arg)->second))) != 0)
						{
							status.at(i) = 0;
							updates(indexes.find(first_arg)->second, indexes.find(second_arg)->second, 
								comb.at(i).at(indexes.find(first_arg)->second), comb.at(i).at(indexes.find(second_arg)->second), i+1);
						}
					}
					else if (comb.at(i).at(indexes.find(first_arg)->second) != comb.at(i).at(indexes.find(second_arg)->second))
					{
						status.at(i) = 0;
						updates(indexes.find(first_arg)->second, indexes.find(second_arg)->second, 
							comb.at(i).at(indexes.find(first_arg)->second), comb.at(i).at(indexes.find(second_arg)->second), i+1);
					}
				}
				else if (type == PATTERN_A || type == PATTERN_I || type == PATTERN_W)
				{
					if (type == PATTERN_A)
					{
						string third_arg = relations_with_two_entity.at(j).parameters.at(2).value;
						ParameterType third_arg_type = relations_with_two_entity.at(j).parameters.at(2).type;
						int left_condition = 1, right_condition = 0;

						if (third_arg_type == ANY)
							third_arg = ""; // remove underscore
						else if (third_arg_type == EXPRESSION)
							right_condition = 1;
						else if (third_arg_type == SUBEXPRESSION)
							right_condition = 2;

						vector<vector<int>> v = _pattern.evaluateAssignV2(first_arg_set, second_arg_set, left_condition, third_arg, right_condition);
						if (v.at(0).size() == 0)
						{
							status.at(i) = 0;
						}
					}
					else if (type == PATTERN_I || type == PATTERN_W)
					{
						vector<vector<int>> v = _pattern.evaluateWhileIfControlVariableV2(first_arg_set, second_arg_set, 1);
						if (v.at(0).size() == 0)
						{
							status.at(i) = 0;
							updates(indexes.find(first_arg)->second, indexes.find(second_arg)->second, 
								comb.at(i).at(indexes.find(first_arg)->second), comb.at(i).at(indexes.find(second_arg)->second), i+1);
						}
					}
				}

				if (compute.size() == 0)
				{
					if (type != WITH && type != PATTERN_A && type != PATTERN_I && type != PATTERN_W)
					{
						status.at(i) = 0;
						updates(indexes.find(first_arg)->second, indexes.find(second_arg)->second, 
							comb.at(i).at(indexes.find(first_arg)->second), comb.at(i).at(indexes.find(second_arg)->second), i+1);
					}
				}
				else if (type != WITH && type != PATTERN_A && type != PATTERN_I && type != PATTERN_W && compute.at(0).size() == 0)
				{
					status.at(i) = 0;
					updates(indexes.find(first_arg)->second, indexes.find(second_arg)->second, 
						comb.at(i).at(indexes.find(first_arg)->second), comb.at(i).at(indexes.find(second_arg)->second), i+1);
				}
			}
		}
	}
	
	if (targets_type.size() == 1 && targets_type.at(0) == BOOL)
	{
		vector<string> s;
		string boo = "true";
		int count = 0;
		for (unsigned i = 0; i < status.size(); i++)
		{
			if (status.at(i) == 1)
				count++;
		}

		if (clause == false || count == 0)
			boo = "false";

		s.push_back(boo);
		result.push_back(s);
	}
	else
	{
		if (targets_type.size() == 1)
		{
			if (clause == true)
			{
				string boo = "true";
				int count = 0;
				for (unsigned i = 0; i < status.size(); i++)
				{
					if (status.at(i) == 1)
						count++;
				}
				if (count == 0)
					boo = "false";

				if (boo.compare("true") == 0)
				{
					int index = indexes.find(targets_name.at(0))->second;
					vector<int> v;
					for (unsigned i = 0; i < status.size(); i++)
						if (status.at(i) == 1)
							v.push_back(comb.at(i).at(index));
					v = RemoveDuplicates(v);

					if (types.find(targets_name.at(0))->second == kVARIABLE) 
					{
						vector<string> s;
						for (unsigned i = 0; i < v.size(); i++)
							s.push_back(PKB::varTable.GetVarName(v.at(i)));
						result.push_back(s);
					}
					else if (types.find(targets_name.at(0))->second == kPROCEDURE)
					{
						vector<string> s;
						for (unsigned i = 0; i < v.size(); i++)
							s.push_back(PKB::procTable.GetProcName(v.at(i)));
						result.push_back(s);
					}
					else
					{
						vector<string> s;
						for (unsigned i = 0; i < v.size(); i++)
						{
							stringstream ss;
							ss << v.at(i);
							s.push_back(ss.str());
						}
						result.push_back(s);
					}
				}
			}
		}
		else
		{
			// for more targets
			string boo = "true";
			int count = 0;
			for (unsigned i = 0; i < status.size(); i++)
			{
				if (status.at(i) == 1)
					count++;
			}
			if (count == 0)
				boo = "false";

			if (boo.compare("true") == 0)
			{
				vector<string> s;
				for (unsigned i = 0; i < status.size(); i++)
				{
					if (status.at(i) == 1)
					{
						stringstream ss;
						string temp;
						for (unsigned j = 0; j < targets_name.size(); j++)
						{
							int index = indexes.find(targets_name.at(j))->second;
							if (types.find(targets_name.at(j))->second == kVARIABLE)
								temp = PKB::varTable.GetVarName(comb.at(i).at(index));
							else if (types.find(targets_name.at(j))->second == kPROCEDURE)
								temp = PKB::procTable.GetProcName(comb.at(i).at(index));
							else
							{
								stringstream ss1;
								ss1 << comb.at(i).at(index);
								temp = ss1.str();
							}

							if (j != targets_name.size() - 1)
								ss << temp << " ";
							else
								ss << temp;
						}

						if (find(s.begin(), s.end(), ss.str()) == s.end())
							s.push_back(ss.str());
					}
				}
					result.push_back(s);
			}
		}
	}

	vector<vector<int>> v1;
	comb = v1;
	vector<int> v2;
	status = v2;
	return result;
}


void QueryEvaluator::updates(int index_first, int index_second, int value_first, int value_second, int start)
{
	for (unsigned i = start; i < comb.size(); i++)
	{
		if (status.at(i) == 1)
		{
			if (comb.at(i).at(index_first) == value_first && comb.at(i).at(index_second) == value_second)
			{
				status.at(i) = 0;
			}
		}
	}
}

void QueryEvaluator::combinations(vector<vector<int>> arr, int i, vector<int> accum)
{
	if (i == arr.size()) // done, no more rows
	{
		comb.push_back(accum); // assuming comb is global
	}
	else
	{
		vector<int> row = arr[i];
		for(unsigned j = 0; j < row.size(); ++j)
		{
			vector<int> tmp(accum);
			tmp.push_back(row[j]);
			combinations(arr,i+1,tmp);

			if ( j % 50 == 0)
			{
				#if !SPA_PROJECT
					if (AbstractWrapper::GlobalStop)
					{
						return;
					}
				#endif
			}
		}
	}
}

string QueryEvaluator::RemoveAttribute(string str)
{
	for (unsigned i = 0; i < str.length(); i++)
		if (str.at(i) == '.')
			return str.substr(0, i);
	return str;
}

vector<int> QueryEvaluator::RemoveDuplicates(vector<int> setA)
{
	sort(setA.begin(), setA.end());
	setA.erase(unique(setA.begin(), setA.end()), setA.end());
	return setA;
}

vector<int> QueryEvaluator::SetIntersection(vector<int> setA, vector<int> setB)
{
	sort(setA.begin(), setA.end());
	sort(setB.begin(), setB.end());

	// remove duplicates
	setA.erase(unique(setA.begin(), setA.end()), setA.end());
	setB.erase(unique(setB.begin(), setB.end()), setB.end());

	vector<int> setC;
	set_intersection(setA.begin(), setA.end(), setB.begin(), setB.end(), back_inserter(setC));

	return setC;
}

vector<int> QueryEvaluator::GetAllProgramLine()
{
	set<int> s = PKB::shortcutTable.GetAllProgramLine();
	vector<int> v(s.begin(), s.end());
	return v;
}

vector<int> QueryEvaluator::GetAllStatement()
{
	set<int> s = PKB::shortcutTable.GetAllStatement();
	vector<int> v(s.begin(), s.end());
	return v;
}

vector<int> QueryEvaluator::GetAllAssign()
{
	set<int> s = PKB::shortcutTable.GetAllAssign();
	vector<int> v(s.begin(), s.end());
	return v;
}

vector<int> QueryEvaluator::GetAllCall()
{
	set<int> s = PKB::shortcutTable.GetAllCall();
	vector<int> v(s.begin(), s.end());
	return v;
}

vector<int> QueryEvaluator::GetAllIf()
{
	set<int> s = PKB::shortcutTable.GetAllIf();
	vector<int> v(s.begin(), s.end());
	return v;
}

vector<int> QueryEvaluator::GetAllWhile()
{
	set<int> s = PKB::shortcutTable.GetAllWhile();
	vector<int> v(s.begin(), s.end());
	return v;
}

vector<int> QueryEvaluator::GetAllConstant()
{
	set<int> s = PKB::shortcutTable.GetAllConstant();
	vector<int> v(s.begin(), s.end());
	return v;
}

vector<int> QueryEvaluator::GetAllProcIndex()
{
	set<int> s = PKB::procTable.GetAllProcIndex();
	vector<int> v(s.begin(), s.end());
	return v;
}

vector<int> QueryEvaluator::GetAllVarIndex()
{
	set<int> s = PKB::varTable.GetAllVarIndex();
	vector<int> v(s.begin(), s.end());
	return v;
}

int QueryEvaluator::GetNumOfEntities(query_relation relation)
{
	if ((relation.parameters.at(0).type != ENTITY) &&
		(relation.parameters.at(0).type != ATTRIBUTE) &&
		(relation.parameters.at(1).type != ENTITY) &&		
		(relation.parameters.at(1).type != ATTRIBUTE))
		return 0;
		
	else if (((relation.parameters.at(0).type == ENTITY) ||
		(relation.parameters.at(0).type == ATTRIBUTE)) &&
		((relation.parameters.at(1).type == ENTITY) ||	
		(relation.parameters.at(1).type == ATTRIBUTE)))
		return 2;

	return 1;
}